package com.snail.monitor;

import com.snail.util.FileUtil;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class MonitorRecord {

    private static MonitorRecord instance = new MonitorRecord();

    private IMonitorCtrl ctrl;

    private List<String> stopKeys = new ArrayList<String>();

    private List<String> downKeys = new ArrayList<String>();

    private long lastTime = System.currentTimeMillis();

    private List<OperateRecordInfo> operateRecList = new ArrayList<OperateRecordInfo>();

    public static final MonitorRecord getInstance() {

        return instance;
    }

    private MonitorRecord() {

    }

    public void keyDown(int keyCode) {
        downKeys.add(keyCode + "");
        if (downKeys.equals(getStopKeys())) {
            downKeys.remove(keyCode + "");
            stopMonitor();
            return;
        }
        addOperateRec(OperateRecordInfo.newOperateRecordInfo(OperateRecordInfo.OP_TYPE_KEYBOARD,
                OperateRecordInfo.OP_CODE_KEY_DOWN, keyCode + ""));
    }

    public void keyUp(int keyCode) {
        downKeys.remove(keyCode + "");
        addOperateRec(OperateRecordInfo.newOperateRecordInfo(OperateRecordInfo.OP_TYPE_KEYBOARD,
                OperateRecordInfo.OP_CODE_KEY_UP, keyCode + ""));
    }

    public void leftDown(int x, int y) {

        addOperateRec(OperateRecordInfo.newOperateRecordInfo(OperateRecordInfo.OP_TYPE_MOUSE,
                OperateRecordInfo.OP_CODE_MOUSE_LEFT_CLICK, x + "," + y));
    }

    public void rightDown(int x, int y) {
        addOperateRec(OperateRecordInfo.newOperateRecordInfo(OperateRecordInfo.OP_TYPE_MOUSE,
                OperateRecordInfo.OP_CODE_MOUSE_RIGHT_CLICK, x + "," + y));
    }

    private void stopMonitor() {
        while (!downKeys.isEmpty()) {
            keyUp(Integer.parseInt(downKeys.get(0).toString()));
        }
        if (getCtrl() != null) {
            getCtrl().stopMonitor();
        }
    }

    public void addOperateRec(OperateRecordInfo info) {
        if (info == null) {
            return;
        }
        String opType = info.getOpType();
        boolean needAddDelayOp = opType.equals(OperateRecordInfo.OP_TYPE_MOUSE);
        if (!needAddDelayOp) {
            int index = getOperateRecList().size() - 1;
            if (index < 0) {
                needAddDelayOp = true;
            } else if (opType.equals(OperateRecordInfo.OP_TYPE_KEYBOARD)) {
                OperateRecordInfo lastOpInfo = (OperateRecordInfo) getOperateRecList().get(index);
                if (lastOpInfo.getOpType().equals(OperateRecordInfo.OP_TYPE_MOUSE)) {
                    needAddDelayOp = true;
                }
            }
        }
        if (needAddDelayOp) {
            long cureentTime = System.currentTimeMillis();
            getOperateRecList().add(
                    OperateRecordInfo.newOperateRecordInfo(OperateRecordInfo.OP_TYPE_DELAY, "",
                            (cureentTime - getLastTime()) + ""));
            setLastTime(cureentTime);
        }
        getOperateRecList().add(info);
    }

    public void saveToFile(String fileName) throws Exception {
        MonitorRecordFormatter formatter = new MonitorRecordFormatter(this);
        String fileContent = formatter.getFormat();
        FileUtil.saveToFile(fileContent, fileName);
    }

    public List<OperateRecordInfo> getOpRecsFromFile(File file) throws Exception {
        List<String> opRecStrs = FileUtil.getContentFromFileByLine(file);
        List<OperateRecordInfo> opRecInfoList = new ArrayList<>();
        for (String opRecStr : opRecStrs) {
            OperateRecordInfo opRecInfo = OperateRecordInfo.newOperateRecordInfo(opRecStr);
            if (opRecInfo != null) {
                opRecInfoList.add(opRecInfo);
            }
        }
        return opRecInfoList;
    }

    public void reset() {
        getOperateRecList().clear();
        setLastTime(System.currentTimeMillis());
    }

    public IMonitorCtrl getCtrl() {
        return ctrl;
    }

    public void setCtrl(IMonitorCtrl ctrl) {
        this.ctrl = ctrl;
    }

    public List<String> getStopKeys() {
        return stopKeys;
    }

    public void setStopKeys(List<String> stopKeys) {
        this.stopKeys = stopKeys;
    }

    public long getLastTime() {
        return this.lastTime;
    }

    public void setLastTime(long lastTime) {
        this.lastTime = lastTime;
    }

    public List<OperateRecordInfo> getOperateRecList() {
        return operateRecList;
    }

    public void setOperateRecList(List<OperateRecordInfo> operateRecList) {
        this.operateRecList = operateRecList;
    }
}
